from errors import Duplicate, Missing
from model.creature import Creature

from .init import IntegrityError, curs

curs.execute(
    """
    CREATE TABLE IF NOT EXISTS creature(
    name TEXT PRIMARY KEY,
    description TEXT,
    country TEXT,
    area TEXT,
    aka TEXT)
    """
)


def _row_to_model(row: tuple) -> Creature:
    name, description, country, area, aka = row
    return Creature(
        name=name,
        country=country,
        area=area,
        description=description,
        aka=aka,
    )


def _model_to_dict(creature: Creature) -> dict:
    return creature.model_dump()


def get_one(name: str) -> Creature:
    query = "SELECT * FROM creature WHERE name=:name"
    params = {"name": name}

    curs.execute(query, params)
    if row := curs.fetchone():
        return _row_to_model(row)
    raise Missing(msg=f"Creature '{name}' not found")


def get_all() -> list[Creature]:
    query = "SELECT * FROM creature"
    curs.execute(query)
    rows = list(curs.fetchall())
    return [_row_to_model(row) for row in rows]


def create(creature: Creature) -> Creature:
    query = """
    INSERT INTO creature
    VALUES (:name, :description, :country, :area, :aka)
    """
    try:
        curs.execute(query, _model_to_dict(creature))
    except IntegrityError as ex:
        raise Duplicate(msg=f"Creature '{creature.name}' already exists") from ex
    return get_one(creature.name)


def modify(name: str, creature: Creature) -> Creature:
    query = """
    UPDATE creature
    SET country = :country,
      name = :name,
      description = :description,
      area = :area,
      aka = :aka
    WHERE name = :name_orig
    """
    params = _model_to_dict(creature)
    params["name_orig"] = name

    curs.execute(query, params)
    if curs.rowcount == 1:
        return get_one(creature.name)
    raise Missing(msg=f"Creature '{name}' not found")


def delete(name: str) -> None:
    query = "DELETE FROM creature WHERE name = :name"
    params = {"name": name}
    curs.execute(query, params)
    if curs.rowcount != 1:
        raise Missing(msg=f"Creature '{name}' not found")
    return None
